From: mjw@wray-m-3.hpl.hp.com Date: Mon, 28 Jun 2004 08:17:15 +0000 (+0000) Subject: bitkeeper revision 1.1010.1.10 (40dfd40bszbCgYF9OJJKWOo1n7X8hw) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~18098^2 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks:///%22http:/www.example.com/cgi/%22https:/%22bookmarks:/?a=commitdiff_plain;h=af551a1bda7ff1390e7b06a992bee4d04d537e32;p=xen.git bitkeeper revision 1.1010.1.10 (40dfd40bszbCgYF9OJJKWOo1n7X8hw) Rename xenctl, move things around. --- diff --git a/.rootkeys b/.rootkeys index 1aabafc723..8418e7c668 100644 --- a/.rootkeys +++ b/.rootkeys @@ -162,10 +162,9 @@ 40278d91ZjLhxdjjrGe8HEdwHLj5xQ tools/examples/netbsd 401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/examples/xc_dom_control.py 401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py -403b7cf7J7FsSSoEPGhx6gXR4pIdZg tools/examples/xc_physinfo.py -40c9c4684Wfg8VgMKtRFa_ULi2e_tQ tools/examples/xm_dom_control.py 40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py 40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults +40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile @@ -200,6 +199,11 @@ 3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py 40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xen/Makefile 40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/xen/lib/__init__.py +40dfd40aMOhnw_cQLve9462UR5yYxQ tools/xen/lib/ext/__init__.py +40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/xen/lib/util/__init__.py +4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xen/lib/util/console_client.py +40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xen/lib/util/ip.py +4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xen/lib/util/tempfile.py 40c9c468SNuObE_YWARyS0hzTPSzKg tools/xen/lib/xend/Args.py 40c9c468Um_qc66OQeLEceIz1pgD5g tools/xen/lib/xend/EventServer.py 40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xen/lib/xend/EventTypes.py @@ -250,13 +254,6 @@ 40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xen/setup.py 40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xen/xend 40cf2937dqM1jWW87O5OoOYND8leuA tools/xen/xm -4055ee41IfFazrwadCH2J72nz-A9YA tools/xenctl/Makefile -4055ee4b_4Rvns_KzE12csI14EKK6Q tools/xenctl/lib/__init__.py -4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xenctl/lib/console_client.py -40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xenctl/lib/ip.py -4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xenctl/lib/tempfile.py -3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xenctl/lib/utils.py -4055ee44Bu6oP7U0WxxXypbUt4dNPQ tools/xenctl/setup.py 40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend-old/Makefile 4055ad95Se-FqttgxollqOAAHB94zA tools/xend-old/lib/__init__.py 4092738fMRGC9fFBcPRCWaJaj9U3ag tools/xend-old/lib/blkif.py @@ -274,6 +271,7 @@ 403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c 403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format 4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1 +40dfd40a0QtsSGigB9TCpVGWZmhlNA tools/xu/Makefile 40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/xu/lib/__init__.py 40dc4076pVeE1kEEWzcUaNZin65kCA tools/xu/lib/domain_controller.h 40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/xu/lib/xu.c diff --git a/tools/Makefile b/tools/Makefile index 69b05709f6..908f49b682 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,17 +5,14 @@ all: $(MAKE) -C misc $(MAKE) -C examples $(MAKE) -C xentrace - $(MAKE) -C xenctl $(MAKE) -C xen install: all $(MAKE) -C xc install $(MAKE) -C xu install $(MAKE) -C misc install - $(MAKE) -C xenctl install $(MAKE) -C examples install $(MAKE) -C xentrace install - $(MAKE) -C xenctl install $(MAKE) -C xen install dist: $(TARGET) @@ -28,6 +25,5 @@ clean: $(MAKE) -C misc clean $(MAKE) -C examples clean $(MAKE) -C xentrace clean - $(MAKE) -C xenctl clean $(MAKE) -C xen clean diff --git a/tools/examples/xc_physinfo.py b/tools/examples/xc_physinfo.py deleted file mode 100644 index 0d9db796c5..0000000000 --- a/tools/examples/xc_physinfo.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -# Get information about the physical host machine - -import Xc - -xc = Xc.new() - -info = xc.physinfo() - -fmt_info = [ ( 'CPU cores', info['cores']), - ('Hyperthreads per core', info['ht_per_core']), - ('CPU Speed (MHz)', info['cpu_khz'] / 1000), - ('Total physical mem (MB)', info['total_pages'] / 256), - ('Free physical mem (MB)', info['free_pages'] / 256) ] - - -for (item, val) in fmt_info: - print "%-23s" % item, ':', val - diff --git a/tools/examples/xm_dom_control.py b/tools/examples/xm_dom_control.py deleted file mode 100755 index 0cb9b100af..0000000000 --- a/tools/examples/xm_dom_control.py +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/env python - -import sys -import re -import string -import time -import os -import os.path -import signal - -from xenmgr import sxp -from xenmgr.XendClient import server - -# usage: xc_dom_control [command] -# -# this script isn't very smart, but it'll do for now. -# - -def usage (rc=0): - if rc: - out = sys.stderr - else: - out = sys.stdout - print >> out, """ -Usage: %s [command] - - help -- print usage - pause [dom] -- pause a domain - unpause [dom] -- un-pause a domain - shutdown [dom] [[-w]] -- request a domain to shutdown (can specify 'all') - (optionally wait for complete shutdown) - destroy [dom] -- immediately terminate a domain - pincpu [dom] [cpu] -- pin a domain to the specified CPU - suspend [dom] [file] -- write domain's memory to a file and terminate - (resume by re-running xc_dom_create with -L option) - unwatch [dom] -- kill the auto-restart daemon for a domain - list -- print info about all domains - listvbds -- print info about all virtual block devs - cpu_bvtset [dom] [mcuadv] [warp] [warpl] [warpu] - -- set BVT scheduling parameters for domain - cpu_bvtslice [slice] -- set default BVT scheduler slice - cpu_atropos_set [dom] [period] [slice] [latency] [xtratime] - -- set Atropos scheduling parameters for domain - cpu_rrobin_slice [slice] -- set Round Robin scheduler slice - vif_stats [dom] [vif] -- get stats for a given network vif - vif_addip [dom] [vif] [ip] -- add an IP address to a given vif - vif_setsched [dom] [vif] [bytes] [usecs] -- rate limit vif bandwidth - vif_getsched [dom] [vif] -- print vif's scheduling parameters - vbd_add [dom] [uname] [dev] [mode] -- make disk/partition uname available to - domain as dev e.g. 'vbd_add 2 phy:sda3 hda1 w' - vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev' -""" % sys.argv[0] - if rc: sys.exit(rc) - -if len(sys.argv) < 2: usage(1) -cmd = sys.argv[1] - -#todo: replace all uses of xc with the new api. -import Xc; xc = Xc.new() - -rc = '' -dom = None - - -def auto_restart_pid_file(dom): - # The auto-restart daemon's pid file. - return '/var/run/xendomains/%d.pid' % dom - -def auto_restart_pid(dom): - watcher = auto_restart_pid_file(dom) - if os.path.isfile(watcher): - fd = open(watcher,'r') - pid = int(fd.readline()) - else: - pid = None - return pid - -def auto_restart_kill(dom): - #todo: replace this - tell xend not to restart any more. - # Kill a domain's auto restart daemon. - pid = auto_restart_pid(dom) - if pid: - os.kill(pid, signal.SIGTERM) - - -if len( sys.argv ) > 2 and re.match('\d+$', sys.argv[2]): - dom = long(sys.argv[2]) - -if cmd == "help": - usage() - -elif cmd == 'pause': - rc = server.xend_domain_pause(dom) - -elif cmd == 'unpause': - rc = server.xend_domain_unpause(dom) - -elif cmd == 'shutdown': - doms = [] - shutdown = [] - if dom != None: - doms = [ dom ] - elif sys.argv[2] == 'all': - doms = server.xend_domains() - doms.remove('0') - for d in doms: - ret = server.xend_domain_shutdown(d) - if ret == 0: - shutdown.append(d) - else: - rc = ret - - wait = (len(sys.argv) == 4 and sys.argv[3] == "-w") - if wait: - # wait for all domains we shut down to terminate - for dom in shutdown: - while True: - info = server.xend_domain(dom) - if not info: break - time.sleep(1) - -elif cmd == 'destroy': - rc = server.xend_domain_halt(dom) - -elif cmd == 'pincpu': - if len(sys.argv) < 4: usage(1) - cpu = int(sys.argv[3]) - rc = server.xend_domain_pincpu(dom, cpu) - -elif cmd == 'list': - print 'Dom Name Mem(MB) CPU State Time(s)' - doms = server.xend_domains() - doms.sort() - for dom in doms: - info = server.xend_domain(dom) - d = {} - d['dom'] = int(dom) - d['name'] = sxp.child_value(info, 'name', '??') - d['mem'] = int(sxp.child_value(info, 'memory', '0')) - d['cpu'] = int(sxp.child_value(info, 'cpu', '0')) - d['state'] = sxp.child_value(info, 'state', '??') - d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0')) - print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)8.2f" % d) - -elif cmd == 'unwatch': - auto_restart_kill(dom) - -elif cmd == 'listvbds': - print 'Dom Dev Mode Size(MB)' - for dom in server.xend_domains(): - for vbd in server.xend_domain_vbds(dom): - info = server.xend_domain_vbd(vbd) - v['vbd'] = vbd - v['size'] = int(sxp.get_child_value(info, 'size', '0')) - v['mode'] = sxp.get_child_value(info, 'mode', '??') - vbd['size_mb'] = vbd['nr_sectors'] / 2048 - print ('%(dom)-4d %(vbd)04x %(mode)-2s %(size)d' % v) - -elif cmd == 'suspend': - if len(sys.argv) < 4: usage(1) - file = os.path.abspath(sys.argv[3]) - auto_restart_kill(dom) - rc = server.xend_domain_save(dom, file, progress=1) - -elif cmd == 'cpu_bvtslice': - if len(sys.argv) < 3: usage(1) - slice = sys.argv[2] - rc = server.xend_node_cpu_bvt_slice_set(slice) - -elif cmd == 'cpu_bvtset': - if len(sys.argv) < 7: usage(1) - (mcuadv, warp, warpl, warpu) = map(int, sys.argv[3:7]) - - rc = server.xend_domain_cpu_bvt_set(dom, mcuadv, warp, warpl, warpu) - -elif cmd == 'vif_stats': - if len(sys.argv) < 4: usage(1) - vif = int(sys.argv[3]) - - print server.xend_domain_vif_stats(dom, vif) - -elif cmd == 'vif_addip': - if len(sys.argv) < 5: usage(1) - vif = int(sys.argv[3]) - ip = sys.argv[4] - rc = server.xend_domain_vif_addip(dom, vif, ip) - -elif cmd == 'vif_setsched': - if len(sys.argv) < 6: usage(1) - (vif, bytes, usecs) = map(int, sys.argv[3:6]) - rc = server.xend_domain_vif_scheduler_set(dom, vif, bytes, usecs) - -elif cmd == 'vif_getsched': - if len(sys.argv) < 4: usage(1) - vif = int(sys.argv[3]) - print server.xend_domain_vif_scheduler_get(dom, vif) - -elif cmd == 'vbd_add': - if len(sys.argv) < 6: usage(1) - uname = sys.argv[3] - dev = sys.argv[4] - mode = sys.argv[5] - try: - vbd = server.xend_domain_vbd_add(dom, uname, dev, mode) - except StandardError, ex: - print "Error:", ex - sys.exit(1) - print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, vbd) - -elif cmd == 'vbd_remove': - if len(sys.argv) < 4: usage(1) - dev = sys.argv[3] - vbd = server.xend_domain_vbd_remove(dom, dev) - if vbd < 0: - print "Failed" - sys.exit(1) - else: - print "Removed disk/partition attached as device %s (%x) in domain %d" % (dev, vbd, dom) - -elif cmd == 'cpu_atropos_set': # args: dom period slice latency xtratime - if len(sys.argv) < 6: usage(1) - (period, slice, latency, xtratime) = map(int, sys.argv[3:7]) - rc = server.xend_domain_cpu_atropos_set( - dom, period, slice, latency, xtratime) - -elif cmd == 'cpu_rrobin_slice': - if len(sys.argv) < 3: usage(1) - slice = int(sys.argv[2]) - rc = server.xend_node_rrobin_set(slice=slice) - -else: - usage(1) - -if rc != '': - print "return code %d" % rc diff --git a/tools/examples/xmdefaults b/tools/examples/xmdefaults index 61ebc5349b..311f38e2d0 100644 --- a/tools/examples/xmdefaults +++ b/tools/examples/xmdefaults @@ -44,10 +44,9 @@ cpu = vmid # set based on vmid (mod number of CPUs) # Number of network interfaces. Default is 1. #nics=1 -# List of MAC addresses for the network interfaces. -# If there aren't enough addresses for all the interfaces -# the rest get random MACs. -#mac = [ "aa:00:00:00:00:11" ] +# Optionally define mac and/or bridge for the network interfaces. +# Random MACs are assigned if not given. +#vif = [ 'mac=aa:00:00:00:00:11, bridge=nbe-br' ] #---------------------------------------------------------------------------- # Define the disk devices you want the domain to have access to, and diff --git a/tools/examples/xmnetbsd b/tools/examples/xmnetbsd new file mode 100644 index 0000000000..0563239464 --- /dev/null +++ b/tools/examples/xmnetbsd @@ -0,0 +1,102 @@ +# -*- mode: python; -*- +#============================================================================ +# Python defaults setup for 'xm create'. +# Edit this file to reflect the configuration of your system. +# This file expects the variable 'vmid' to be set. +#============================================================================ + +def config_usage (): + print >>sys.stderr,""" +The config file '%s' requires the following variable to be defined: + vmid -- Numeric identifier for the new domain, used to calculate + the VM's IP address and root partition. E.g. -Dvmid=1 +""" % config_file + + +try: + vmid = int(vmid) # convert to integer +except: + raise ValueError, "Variable 'vmid' must be an integer" + +if vmid <= 0: + raise ValueError, "Variable 'vmid' must be greater than 0" + +#---------------------------------------------------------------------------- +# Kernel image file. +image = "/boot/netbsd" + +# The domain build function. +builder='netbsd' + +# Initial memory allocation (in megabytes) for the new domain. +memory = 16 + +# A handy name for your new domain. +name = "NetBSD VM %d" % vmid + +#---------------------------------------------------------------------------- +# Define network interfaces. + +# Number of network interfaces. Default is 1. +#nics=1 + +# Optionally define mac and/or bridge for the network interfaces. +# Random MACs are assigned if not given. +#vif = [ 'mac=aa:00:00:00:00:11, bridge=nbe-br' ] + +# Specify IP address(es), for the new domain. You need to +# configure IP addrs within the domain just as you do normally. This +# is just to let Xen know about them so it can route packets +# appropriately. + +#ipaddr = [ xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),vmid), +# xenctl.utils.add_offset_to_ip('169.254.1.0',vmid), +# ] + +#---------------------------------------------------------------------------- +# Define the disk devices you want the domain to have access to, and +# what you want them accessible as. +# Each disk entry is of the form phy:DEV,VDEV,MODE +# where DEV is the device, VDEV is the device name the domain will see, +# and MODE is r for read-only, w for read-write. + +#disk = [ 'phy:sda%d,sda1,w' % (7+vmid), +# 'phy:sda6,sda6,r' ] + +#---------------------------------------------------------------------------- +# Set the kernel command line for the new domain. +# You only need to define the IP parameters and hostname if the domain's +# IP config doesn't, e.g. in ifcfg-eth0 or via DHCP. +# You can use 'extra' to set the runlevel and custom environment +# variables used by custom rc scripts (e.g. VMID=, usr= ). + +# Set if you want dhcp to allocate the IP address. +#dhcp="dhcp" +# Set netmask. +#netmask= +# Set default gateway. +#gateway= +# Set the hostname. +#hostname= "vm%d" % vmid + +# Set root device. +root = "/dev/sda1 ro" + +# Root device for nfs. +#root = "/dev/nfs" +# The nfs server. +#nfs_server = '169.254.1.0' +# Root directory on the nfs server. +#nfs_root = '/full/path/to/root/directory' + +# Sets runlevel 4 and the device for /usr. +#extra = "4 VMID=%d usr=/dev/sda6" % vmid +extra = "4 VMID=%d bootdev=xennet0" % vmid + + +#---------------------------------------------------------------------------- +# Set according to whether you want the domain restarted when it exits. +# The default is False. +#restart = True + +#============================================================================ diff --git a/tools/xen/lib/ext/__init__.py b/tools/xen/lib/ext/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/xen/lib/ext/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/xen/lib/util/__init__.py b/tools/xen/lib/util/__init__.py new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/xen/lib/util/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/xen/lib/util/console_client.py b/tools/xen/lib/util/console_client.py new file mode 100644 index 0000000000..7ac63aeb75 --- /dev/null +++ b/tools/xen/lib/util/console_client.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +############################################## +# Console client for Xen guest OSes +# Copyright (c) 2004, K A Fraser +############################################## + +import errno, os, signal, socket, struct, sys + +from termios import * +# Indexes into termios.tcgetattr() list. +IFLAG = 0 +OFLAG = 1 +CFLAG = 2 +LFLAG = 3 +ISPEED = 4 +OSPEED = 5 +CC = 6 + +def __child_death(signum, frame): + global stop + stop = True + +def __recv_from_sock(sock): + global stop + stop = False + while not stop: + try: + data = sock.recv(1024) + os.write(1, data) + except socket.error, error: + if error[0] != errno.EINTR: + raise + os.wait() + +def __send_to_sock(sock): + while 1: + data = os.read(0,1024) + if ord(data[0]) == ord(']')-64: + break + try: + sock.send(data) + except socket.error, error: + if error[0] == errno.EPIPE: + sys.exit(0) + if error[0] != errno.EINTR: + raise + sys.exit(0) + +def connect(host,port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock.connect((host,port)) + + oattrs = tcgetattr(0) + nattrs = tcgetattr(0) + nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) + nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST) + nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB) + nattrs[CFLAG] = nattrs[CFLAG] | CS8 + nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG) + nattrs[CC][VMIN] = 1 + nattrs[CC][VTIME] = 0 + + if os.fork(): + signal.signal(signal.SIGCHLD, __child_death) + print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********" + tcsetattr(0, TCSAFLUSH, nattrs) + try: + __recv_from_sock(sock) + finally: + tcsetattr(0, TCSAFLUSH, oattrs) + print + print "************ REMOTE CONSOLE EXITED *****************" + else: + signal.signal(signal.SIGPIPE, signal.SIG_IGN) + __send_to_sock(sock) + +if __name__ == '__main__': + if len(sys.argv) != 3: + print sys.argv[0] + " " + sys.exit(1) + connect(str(sys.argv[1]),int(sys.argv[2])) diff --git a/tools/xen/lib/util/ip.py b/tools/xen/lib/util/ip.py new file mode 100644 index 0000000000..8396e0d014 --- /dev/null +++ b/tools/xen/lib/util/ip.py @@ -0,0 +1,113 @@ +import os +import re +import socket +import struct + +def readlines(fd): + """Version of readlines safe against EINTR. + """ + import errno + + lines = [] + while 1: + try: + line = fd.readline() + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + if line == '': break + lines.append(line) + return lines + +def readline(fd): + """Version of readline safe against EINTR. + """ + while 1: + try: + return fd.readline() + except IOError, ex: + if ex.errno == errno.EINTR: + continue + else: + raise + +##### Networking-related functions + +"""Bridge for network backend. +When bridging is used, eth0 may not have an IP address, +as it may have been moved onto the bridge. +""" +NBE_BRIDGE = 'nbe-br' + +def get_current_ipaddr(dev='eth0'): + """Return a string containing the primary IP address for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', + line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipaddr(NBE_BRIDGE) + return None + +def get_current_ipmask(dev='eth0'): + """Return a string containing the primary IP netmask for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', + line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipmask(NBE_BRIDGE) + return None + +def get_current_ipgw(dev='eth0'): + """Return a string containing the IP gateway for the given + network interface (default 'eth0'). + """ + fd = os.popen( '/sbin/route -n' ) + lines = readlines(fd) + for line in lines: + m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + + '\s+\S+\s+\S*G.*' + dev + '.*', line ) + if m: + return m.group(1) + if dev == 'eth0': + return get_current_ipgw(NBE_BRIDGE) + return None + +def inet_aton(addr): + """Convert an IP addr in IPv4 dot notation into an int. + """ + b = socket.inet_aton(addr) + return struct.unpack('!I', b)[0] + +def inet_ntoa(n): + """Convert an int into an IP addr in IPv4 dot notation. + """ + b = struct.pack('!I', n) + return socket.inet_ntoa(b) + +def add_offset_to_ip(addr, offset): + """Add a numerical offset to an IP addr in IPv4 dot notation. + """ + n = inet_aton(addr) + n += offset + return inet_ntoa(n) + +def check_subnet( ip, network, netmask ): + n_ip = inet_aton(ip) + n_net = inet_aton(network) + n_mask = inet_aton(netmask) + return (n_ip & n_mask) == (n_net & n_mask) + diff --git a/tools/xen/lib/util/tempfile.py b/tools/xen/lib/util/tempfile.py new file mode 100644 index 0000000000..756d8c8727 --- /dev/null +++ b/tools/xen/lib/util/tempfile.py @@ -0,0 +1,451 @@ +"""Temporary files. + +This module provides generic, low- and high-level interfaces for +creating temporary files and directories. The interfaces listed +as "safe" just below can be used without fear of race conditions. +Those listed as "unsafe" cannot, and are provided for backward +compatibility only. + +This module also provides some data items to the user: + + TMP_MAX - maximum number of names that will be tried before + giving up. + template - the default prefix for all temporary names. + You may change this to control the default prefix. + tempdir - If this is set to a string before the first use of + any routine from this module, it will be considered as + another candidate location to store temporary files. +""" + +__all__ = [ + "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces + "mkstemp", "mkdtemp", # low level safe interfaces + "mktemp", # deprecated unsafe interface + "TMP_MAX", "gettempprefix", # constants + "tempdir", "gettempdir" + ] + + +# Imports. + +import os as _os +import errno as _errno +from random import Random as _Random + +if _os.name == 'mac': + import Carbon.Folder as _Folder + import Carbon.Folders as _Folders + +try: + import fcntl as _fcntl + # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets + # imported, and we don't get an ImportError then. Provoke + # an AttributeError instead in that case. + _fcntl.fcntl +except (ImportError, AttributeError): + def _set_cloexec(fd): + pass +else: + def _set_cloexec(fd): + flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) + if flags >= 0: + # flags read successfully, modify + flags |= _fcntl.FD_CLOEXEC + _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) + + +try: + import thread as _thread +except ImportError: + import dummy_thread as _thread +_allocate_lock = _thread.allocate_lock + +_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL +if hasattr(_os, 'O_NOINHERIT'): + _text_openflags |= _os.O_NOINHERIT +if hasattr(_os, 'O_NOFOLLOW'): + _text_openflags |= _os.O_NOFOLLOW + +_bin_openflags = _text_openflags +if hasattr(_os, 'O_BINARY'): + _bin_openflags |= _os.O_BINARY + +if hasattr(_os, 'TMP_MAX'): + TMP_MAX = _os.TMP_MAX +else: + TMP_MAX = 10000 + +template = "tmp" + +tempdir = None + +# Internal routines. + +_once_lock = _allocate_lock() + +class _RandomNameSequence: + """An instance of _RandomNameSequence generates an endless + sequence of unpredictable strings which can safely be incorporated + into file names. Each string is six characters long. Multiple + threads can safely use the same instance at the same time. + + _RandomNameSequence is an iterator.""" + + characters = ("abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "0123456789-_") + + def __init__(self): + self.mutex = _allocate_lock() + self.rng = _Random() + self.normcase = _os.path.normcase + + def __iter__(self): + return self + + def next(self): + m = self.mutex + c = self.characters + choose = self.rng.choice + + m.acquire() + try: + letters = [choose(c) for dummy in "123456"] + finally: + m.release() + + return self.normcase(''.join(letters)) + +def _candidate_tempdir_list(): + """Generate a list of candidate temporary directories which + _get_default_tempdir will try.""" + + dirlist = [] + + # First, try the environment. + for envname in 'TMPDIR', 'TEMP', 'TMP': + dirname = _os.getenv(envname) + if dirname: dirlist.append(dirname) + + # Failing that, try OS-specific locations. + if _os.name == 'mac': + try: + fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk, + _Folders.kTemporaryFolderType, 1) + dirname = fsr.as_pathname() + dirlist.append(dirname) + except _Folder.error: + pass + elif _os.name == 'riscos': + dirname = _os.getenv('Wimp$ScrapDir') + if dirname: dirlist.append(dirname) + elif _os.name == 'nt': + dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) + else: + dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) + + # As a last resort, the current directory. + try: + dirlist.append(_os.getcwd()) + except (AttributeError, _os.error): + dirlist.append(_os.curdir) + + return dirlist + +def _get_default_tempdir(): + """Calculate the default directory to use for temporary files. + This routine should be called exactly once. + + We determine whether or not a candidate temp dir is usable by + trying to create and write to a file in that directory. If this + is successful, the test file is deleted. To prevent denial of + service, the name of the test file must be randomized.""" + + namer = _RandomNameSequence() + dirlist = _candidate_tempdir_list() + flags = _text_openflags + + for dir in dirlist: + if dir != _os.curdir: + dir = _os.path.normcase(_os.path.abspath(dir)) + # Try only a few names per directory. + for seq in xrange(100): + name = namer.next() + filename = _os.path.join(dir, name) + try: + fd = _os.open(filename, flags, 0600) + fp = _os.fdopen(fd, 'w') + fp.write('blat') + fp.close() + _os.unlink(filename) + del fp, fd + return dir + except (OSError, IOError), e: + if e[0] != _errno.EEXIST: + break # no point trying more names in this directory + pass + raise IOError, (_errno.ENOENT, + ("No usable temporary directory found in %s" % dirlist)) + +_name_sequence = None + +def _get_candidate_names(): + """Common setup sequence for all user-callable interfaces.""" + + global _name_sequence + if _name_sequence is None: + _once_lock.acquire() + try: + if _name_sequence is None: + _name_sequence = _RandomNameSequence() + finally: + _once_lock.release() + return _name_sequence + + +def _mkstemp_inner(dir, pre, suf, flags): + """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, pre + name + suf) + try: + fd = _os.open(file, flags, 0600) + _set_cloexec(fd) + return (fd, file) + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + + raise IOError, (_errno.EEXIST, "No usable temporary file name found") + + +# User visible interfaces. + +def gettempprefix(): + """Accessor for tempdir.template.""" + return template + +tempdir = None + +def gettempdir(): + """Accessor for tempdir.tempdir.""" + global tempdir + if tempdir is None: + _once_lock.acquire() + try: + if tempdir is None: + tempdir = _get_default_tempdir() + finally: + _once_lock.release() + return tempdir + +def mkstemp(suffix="", prefix=template, dir=None, text=False): + """mkstemp([suffix, [prefix, [dir, [text]]]]) + User-callable function to create and return a unique temporary + file. The return value is a pair (fd, name) where fd is the + file descriptor returned by os.open, and name is the filename. + + If 'suffix' is specified, the file name will end with that suffix, + otherwise there will be no suffix. + + If 'prefix' is specified, the file name will begin with that prefix, + otherwise a default prefix is used. + + If 'dir' is specified, the file will be created in that directory, + otherwise a default directory is used. + + If 'text' is specified and true, the file is opened in text + mode. Else (the default) the file is opened in binary mode. On + some operating systems, this makes no difference. + + The file is readable and writable only by the creating user ID. + If the operating system uses permission bits to indicate whether a + file is executable, the file is executable by no one. The file + descriptor is not inherited by children of this process. + + Caller is responsible for deleting the file when done with it. + """ + + if dir is None: + dir = gettempdir() + + if text: + flags = _text_openflags + else: + flags = _bin_openflags + + return _mkstemp_inner(dir, prefix, suffix, flags) + + +def mkdtemp(suffix="", prefix=template, dir=None): + """mkdtemp([suffix, [prefix, [dir]]]) + User-callable function to create and return a unique temporary + directory. The return value is the pathname of the directory. + + Arguments are as for mkstemp, except that the 'text' argument is + not accepted. + + The directory is readable, writable, and searchable only by the + creating user. + + Caller is responsible for deleting the directory when done with it. + """ + + if dir is None: + dir = gettempdir() + + names = _get_candidate_names() + + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + try: + _os.mkdir(file, 0700) + return file + except OSError, e: + if e.errno == _errno.EEXIST: + continue # try again + raise + + raise IOError, (_errno.EEXIST, "No usable temporary directory name found") + +def mktemp(suffix="", prefix=template, dir=None): + """mktemp([suffix, [prefix, [dir]]]) + User-callable function to return a unique temporary file name. The + file is not created. + + Arguments are as for mkstemp, except that the 'text' argument is + not accepted. + + This function is unsafe and should not be used. The file name + refers to a file that did not exist at some point, but by the time + you get around to creating it, someone else may have beaten you to + the punch. + """ + +## from warnings import warn as _warn +## _warn("mktemp is a potential security risk to your program", +## RuntimeWarning, stacklevel=2) + + if dir is None: + dir = gettempdir() + + names = _get_candidate_names() + for seq in xrange(TMP_MAX): + name = names.next() + file = _os.path.join(dir, prefix + name + suffix) + if not _os.path.exists(file): + return file + + raise IOError, (_errno.EEXIST, "No usable temporary filename found") + +class _TemporaryFileWrapper: + """Temporary file wrapper + + This class provides a wrapper around files opened for + temporary use. In particular, it seeks to automatically + remove the file when it is no longer needed. + """ + + def __init__(self, file, name): + self.file = file + self.name = name + self.close_called = False + + def __getattr__(self, name): + file = self.__dict__['file'] + a = getattr(file, name) + if type(a) != type(0): + setattr(self, name, a) + return a + + # NT provides delete-on-close as a primitive, so we don't need + # the wrapper to do anything special. We still use it so that + # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. + if _os.name != 'nt': + + # Cache the unlinker so we don't get spurious errors at + # shutdown when the module-level "os" is None'd out. Note + # that this must be referenced as self.unlink, because the + # name TemporaryFileWrapper may also get None'd out before + # __del__ is called. + unlink = _os.unlink + + def close(self): + if not self.close_called: + self.close_called = True + self.file.close() + self.unlink(self.name) + + def __del__(self): + self.close() + +def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=None): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'dir' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object; the name of the file is accessible as + file.name. The file will be automatically deleted when it is + closed. + """ + + if dir is None: + dir = gettempdir() + + if 'b' in mode: + flags = _bin_openflags + else: + flags = _text_openflags + + # Setting O_TEMPORARY in the flags causes the OS to delete + # the file when it is closed. This is only supported by Windows. + if _os.name == 'nt': + flags |= _os.O_TEMPORARY + + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + file = _os.fdopen(fd, mode, bufsize) + return _TemporaryFileWrapper(file, name) + +if _os.name != 'posix' or _os.sys.platform == 'cygwin': + # On non-POSIX and Cygwin systems, assume that we cannot unlink a file + # while it is open. + TemporaryFile = NamedTemporaryFile + +else: + def TemporaryFile(mode='w+b', bufsize=-1, suffix="", + prefix=template, dir=None): + """Create and return a temporary file. + Arguments: + 'prefix', 'suffix', 'directory' -- as for mkstemp. + 'mode' -- the mode argument to os.fdopen (default "w+b"). + 'bufsize' -- the buffer size argument to os.fdopen (default -1). + The file is created as mkstemp() would do it. + + Returns a file object. The file has no name, and will cease to + exist when it is closed. + """ + + if dir is None: + dir = gettempdir() + + if 'b' in mode: + flags = _bin_openflags + else: + flags = _text_openflags + + (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) + try: + _os.unlink(name) + return _os.fdopen(fd, mode, bufsize) + except: + _os.close(fd) + raise diff --git a/tools/xen/lib/xm/main.py b/tools/xen/lib/xm/main.py index d03ceae7f2..84abc7a867 100644 --- a/tools/xen/lib/xm/main.py +++ b/tools/xen/lib/xm/main.py @@ -439,7 +439,7 @@ class ProgConsole(Prog): if not console: self.err("No console information") port = sxp.child_value(console, "port") - from xenctl import console_client + from xen.util import console_client console_client.connect("localhost", int(port)) xm.prog(ProgConsole) diff --git a/tools/xen/setup.py b/tools/xen/setup.py index e099e00166..1f0e959d08 100644 --- a/tools/xen/setup.py +++ b/tools/xen/setup.py @@ -8,6 +8,7 @@ setup(name = 'xen', author_email = 'mike.wray@hp.com', packages = ['xen', 'xen.ext', + 'xen.util', 'xen.xend', 'xen.xend.server', 'xen.xm', diff --git a/tools/xenctl/Makefile b/tools/xenctl/Makefile deleted file mode 100644 index 7dc74a1072..0000000000 --- a/tools/xenctl/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -all: - python setup.py build - -install: all - if [ "$(prefix)" = "" ]; then \ - python setup.py install; \ - elif [ "$(dist)" = "yes" ]; then \ - python setup.py install --home="$(prefix)"; \ - else \ - python setup.py install --root="$(prefix)"; \ - fi - -clean: - rm -rf build *.pyc *.pyo *.o *.a *~ diff --git a/tools/xenctl/lib/__init__.py b/tools/xenctl/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/xenctl/lib/console_client.py b/tools/xenctl/lib/console_client.py deleted file mode 100644 index 7ac63aeb75..0000000000 --- a/tools/xenctl/lib/console_client.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -############################################## -# Console client for Xen guest OSes -# Copyright (c) 2004, K A Fraser -############################################## - -import errno, os, signal, socket, struct, sys - -from termios import * -# Indexes into termios.tcgetattr() list. -IFLAG = 0 -OFLAG = 1 -CFLAG = 2 -LFLAG = 3 -ISPEED = 4 -OSPEED = 5 -CC = 6 - -def __child_death(signum, frame): - global stop - stop = True - -def __recv_from_sock(sock): - global stop - stop = False - while not stop: - try: - data = sock.recv(1024) - os.write(1, data) - except socket.error, error: - if error[0] != errno.EINTR: - raise - os.wait() - -def __send_to_sock(sock): - while 1: - data = os.read(0,1024) - if ord(data[0]) == ord(']')-64: - break - try: - sock.send(data) - except socket.error, error: - if error[0] == errno.EPIPE: - sys.exit(0) - if error[0] != errno.EINTR: - raise - sys.exit(0) - -def connect(host,port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.connect((host,port)) - - oattrs = tcgetattr(0) - nattrs = tcgetattr(0) - nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) - nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST) - nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB) - nattrs[CFLAG] = nattrs[CFLAG] | CS8 - nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG) - nattrs[CC][VMIN] = 1 - nattrs[CC][VTIME] = 0 - - if os.fork(): - signal.signal(signal.SIGCHLD, __child_death) - print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********" - tcsetattr(0, TCSAFLUSH, nattrs) - try: - __recv_from_sock(sock) - finally: - tcsetattr(0, TCSAFLUSH, oattrs) - print - print "************ REMOTE CONSOLE EXITED *****************" - else: - signal.signal(signal.SIGPIPE, signal.SIG_IGN) - __send_to_sock(sock) - -if __name__ == '__main__': - if len(sys.argv) != 3: - print sys.argv[0] + " " - sys.exit(1) - connect(str(sys.argv[1]),int(sys.argv[2])) diff --git a/tools/xenctl/lib/ip.py b/tools/xenctl/lib/ip.py deleted file mode 100644 index 8396e0d014..0000000000 --- a/tools/xenctl/lib/ip.py +++ /dev/null @@ -1,113 +0,0 @@ -import os -import re -import socket -import struct - -def readlines(fd): - """Version of readlines safe against EINTR. - """ - import errno - - lines = [] - while 1: - try: - line = fd.readline() - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - if line == '': break - lines.append(line) - return lines - -def readline(fd): - """Version of readline safe against EINTR. - """ - while 1: - try: - return fd.readline() - except IOError, ex: - if ex.errno == errno.EINTR: - continue - else: - raise - -##### Networking-related functions - -"""Bridge for network backend. -When bridging is used, eth0 may not have an IP address, -as it may have been moved onto the bridge. -""" -NBE_BRIDGE = 'nbe-br' - -def get_current_ipaddr(dev='eth0'): - """Return a string containing the primary IP address for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', - line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipaddr(NBE_BRIDGE) - return None - -def get_current_ipmask(dev='eth0'): - """Return a string containing the primary IP netmask for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', - line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipmask(NBE_BRIDGE) - return None - -def get_current_ipgw(dev='eth0'): - """Return a string containing the IP gateway for the given - network interface (default 'eth0'). - """ - fd = os.popen( '/sbin/route -n' ) - lines = readlines(fd) - for line in lines: - m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + - '\s+\S+\s+\S*G.*' + dev + '.*', line ) - if m: - return m.group(1) - if dev == 'eth0': - return get_current_ipgw(NBE_BRIDGE) - return None - -def inet_aton(addr): - """Convert an IP addr in IPv4 dot notation into an int. - """ - b = socket.inet_aton(addr) - return struct.unpack('!I', b)[0] - -def inet_ntoa(n): - """Convert an int into an IP addr in IPv4 dot notation. - """ - b = struct.pack('!I', n) - return socket.inet_ntoa(b) - -def add_offset_to_ip(addr, offset): - """Add a numerical offset to an IP addr in IPv4 dot notation. - """ - n = inet_aton(addr) - n += offset - return inet_ntoa(n) - -def check_subnet( ip, network, netmask ): - n_ip = inet_aton(ip) - n_net = inet_aton(network) - n_mask = inet_aton(netmask) - return (n_ip & n_mask) == (n_net & n_mask) - diff --git a/tools/xenctl/lib/tempfile.py b/tools/xenctl/lib/tempfile.py deleted file mode 100644 index 756d8c8727..0000000000 --- a/tools/xenctl/lib/tempfile.py +++ /dev/null @@ -1,451 +0,0 @@ -"""Temporary files. - -This module provides generic, low- and high-level interfaces for -creating temporary files and directories. The interfaces listed -as "safe" just below can be used without fear of race conditions. -Those listed as "unsafe" cannot, and are provided for backward -compatibility only. - -This module also provides some data items to the user: - - TMP_MAX - maximum number of names that will be tried before - giving up. - template - the default prefix for all temporary names. - You may change this to control the default prefix. - tempdir - If this is set to a string before the first use of - any routine from this module, it will be considered as - another candidate location to store temporary files. -""" - -__all__ = [ - "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces - "mkstemp", "mkdtemp", # low level safe interfaces - "mktemp", # deprecated unsafe interface - "TMP_MAX", "gettempprefix", # constants - "tempdir", "gettempdir" - ] - - -# Imports. - -import os as _os -import errno as _errno -from random import Random as _Random - -if _os.name == 'mac': - import Carbon.Folder as _Folder - import Carbon.Folders as _Folders - -try: - import fcntl as _fcntl - # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets - # imported, and we don't get an ImportError then. Provoke - # an AttributeError instead in that case. - _fcntl.fcntl -except (ImportError, AttributeError): - def _set_cloexec(fd): - pass -else: - def _set_cloexec(fd): - flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) - if flags >= 0: - # flags read successfully, modify - flags |= _fcntl.FD_CLOEXEC - _fcntl.fcntl(fd, _fcntl.F_SETFD, flags) - - -try: - import thread as _thread -except ImportError: - import dummy_thread as _thread -_allocate_lock = _thread.allocate_lock - -_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL -if hasattr(_os, 'O_NOINHERIT'): - _text_openflags |= _os.O_NOINHERIT -if hasattr(_os, 'O_NOFOLLOW'): - _text_openflags |= _os.O_NOFOLLOW - -_bin_openflags = _text_openflags -if hasattr(_os, 'O_BINARY'): - _bin_openflags |= _os.O_BINARY - -if hasattr(_os, 'TMP_MAX'): - TMP_MAX = _os.TMP_MAX -else: - TMP_MAX = 10000 - -template = "tmp" - -tempdir = None - -# Internal routines. - -_once_lock = _allocate_lock() - -class _RandomNameSequence: - """An instance of _RandomNameSequence generates an endless - sequence of unpredictable strings which can safely be incorporated - into file names. Each string is six characters long. Multiple - threads can safely use the same instance at the same time. - - _RandomNameSequence is an iterator.""" - - characters = ("abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "0123456789-_") - - def __init__(self): - self.mutex = _allocate_lock() - self.rng = _Random() - self.normcase = _os.path.normcase - - def __iter__(self): - return self - - def next(self): - m = self.mutex - c = self.characters - choose = self.rng.choice - - m.acquire() - try: - letters = [choose(c) for dummy in "123456"] - finally: - m.release() - - return self.normcase(''.join(letters)) - -def _candidate_tempdir_list(): - """Generate a list of candidate temporary directories which - _get_default_tempdir will try.""" - - dirlist = [] - - # First, try the environment. - for envname in 'TMPDIR', 'TEMP', 'TMP': - dirname = _os.getenv(envname) - if dirname: dirlist.append(dirname) - - # Failing that, try OS-specific locations. - if _os.name == 'mac': - try: - fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk, - _Folders.kTemporaryFolderType, 1) - dirname = fsr.as_pathname() - dirlist.append(dirname) - except _Folder.error: - pass - elif _os.name == 'riscos': - dirname = _os.getenv('Wimp$ScrapDir') - if dirname: dirlist.append(dirname) - elif _os.name == 'nt': - dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ]) - else: - dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ]) - - # As a last resort, the current directory. - try: - dirlist.append(_os.getcwd()) - except (AttributeError, _os.error): - dirlist.append(_os.curdir) - - return dirlist - -def _get_default_tempdir(): - """Calculate the default directory to use for temporary files. - This routine should be called exactly once. - - We determine whether or not a candidate temp dir is usable by - trying to create and write to a file in that directory. If this - is successful, the test file is deleted. To prevent denial of - service, the name of the test file must be randomized.""" - - namer = _RandomNameSequence() - dirlist = _candidate_tempdir_list() - flags = _text_openflags - - for dir in dirlist: - if dir != _os.curdir: - dir = _os.path.normcase(_os.path.abspath(dir)) - # Try only a few names per directory. - for seq in xrange(100): - name = namer.next() - filename = _os.path.join(dir, name) - try: - fd = _os.open(filename, flags, 0600) - fp = _os.fdopen(fd, 'w') - fp.write('blat') - fp.close() - _os.unlink(filename) - del fp, fd - return dir - except (OSError, IOError), e: - if e[0] != _errno.EEXIST: - break # no point trying more names in this directory - pass - raise IOError, (_errno.ENOENT, - ("No usable temporary directory found in %s" % dirlist)) - -_name_sequence = None - -def _get_candidate_names(): - """Common setup sequence for all user-callable interfaces.""" - - global _name_sequence - if _name_sequence is None: - _once_lock.acquire() - try: - if _name_sequence is None: - _name_sequence = _RandomNameSequence() - finally: - _once_lock.release() - return _name_sequence - - -def _mkstemp_inner(dir, pre, suf, flags): - """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile.""" - - names = _get_candidate_names() - - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, pre + name + suf) - try: - fd = _os.open(file, flags, 0600) - _set_cloexec(fd) - return (fd, file) - except OSError, e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError, (_errno.EEXIST, "No usable temporary file name found") - - -# User visible interfaces. - -def gettempprefix(): - """Accessor for tempdir.template.""" - return template - -tempdir = None - -def gettempdir(): - """Accessor for tempdir.tempdir.""" - global tempdir - if tempdir is None: - _once_lock.acquire() - try: - if tempdir is None: - tempdir = _get_default_tempdir() - finally: - _once_lock.release() - return tempdir - -def mkstemp(suffix="", prefix=template, dir=None, text=False): - """mkstemp([suffix, [prefix, [dir, [text]]]]) - User-callable function to create and return a unique temporary - file. The return value is a pair (fd, name) where fd is the - file descriptor returned by os.open, and name is the filename. - - If 'suffix' is specified, the file name will end with that suffix, - otherwise there will be no suffix. - - If 'prefix' is specified, the file name will begin with that prefix, - otherwise a default prefix is used. - - If 'dir' is specified, the file will be created in that directory, - otherwise a default directory is used. - - If 'text' is specified and true, the file is opened in text - mode. Else (the default) the file is opened in binary mode. On - some operating systems, this makes no difference. - - The file is readable and writable only by the creating user ID. - If the operating system uses permission bits to indicate whether a - file is executable, the file is executable by no one. The file - descriptor is not inherited by children of this process. - - Caller is responsible for deleting the file when done with it. - """ - - if dir is None: - dir = gettempdir() - - if text: - flags = _text_openflags - else: - flags = _bin_openflags - - return _mkstemp_inner(dir, prefix, suffix, flags) - - -def mkdtemp(suffix="", prefix=template, dir=None): - """mkdtemp([suffix, [prefix, [dir]]]) - User-callable function to create and return a unique temporary - directory. The return value is the pathname of the directory. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - The directory is readable, writable, and searchable only by the - creating user. - - Caller is responsible for deleting the directory when done with it. - """ - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, prefix + name + suffix) - try: - _os.mkdir(file, 0700) - return file - except OSError, e: - if e.errno == _errno.EEXIST: - continue # try again - raise - - raise IOError, (_errno.EEXIST, "No usable temporary directory name found") - -def mktemp(suffix="", prefix=template, dir=None): - """mktemp([suffix, [prefix, [dir]]]) - User-callable function to return a unique temporary file name. The - file is not created. - - Arguments are as for mkstemp, except that the 'text' argument is - not accepted. - - This function is unsafe and should not be used. The file name - refers to a file that did not exist at some point, but by the time - you get around to creating it, someone else may have beaten you to - the punch. - """ - -## from warnings import warn as _warn -## _warn("mktemp is a potential security risk to your program", -## RuntimeWarning, stacklevel=2) - - if dir is None: - dir = gettempdir() - - names = _get_candidate_names() - for seq in xrange(TMP_MAX): - name = names.next() - file = _os.path.join(dir, prefix + name + suffix) - if not _os.path.exists(file): - return file - - raise IOError, (_errno.EEXIST, "No usable temporary filename found") - -class _TemporaryFileWrapper: - """Temporary file wrapper - - This class provides a wrapper around files opened for - temporary use. In particular, it seeks to automatically - remove the file when it is no longer needed. - """ - - def __init__(self, file, name): - self.file = file - self.name = name - self.close_called = False - - def __getattr__(self, name): - file = self.__dict__['file'] - a = getattr(file, name) - if type(a) != type(0): - setattr(self, name, a) - return a - - # NT provides delete-on-close as a primitive, so we don't need - # the wrapper to do anything special. We still use it so that - # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. - if _os.name != 'nt': - - # Cache the unlinker so we don't get spurious errors at - # shutdown when the module-level "os" is None'd out. Note - # that this must be referenced as self.unlink, because the - # name TemporaryFileWrapper may also get None'd out before - # __del__ is called. - unlink = _os.unlink - - def close(self): - if not self.close_called: - self.close_called = True - self.file.close() - self.unlink(self.name) - - def __del__(self): - self.close() - -def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", - prefix=template, dir=None): - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'dir' -- as for mkstemp. - 'mode' -- the mode argument to os.fdopen (default "w+b"). - 'bufsize' -- the buffer size argument to os.fdopen (default -1). - The file is created as mkstemp() would do it. - - Returns a file object; the name of the file is accessible as - file.name. The file will be automatically deleted when it is - closed. - """ - - if dir is None: - dir = gettempdir() - - if 'b' in mode: - flags = _bin_openflags - else: - flags = _text_openflags - - # Setting O_TEMPORARY in the flags causes the OS to delete - # the file when it is closed. This is only supported by Windows. - if _os.name == 'nt': - flags |= _os.O_TEMPORARY - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - file = _os.fdopen(fd, mode, bufsize) - return _TemporaryFileWrapper(file, name) - -if _os.name != 'posix' or _os.sys.platform == 'cygwin': - # On non-POSIX and Cygwin systems, assume that we cannot unlink a file - # while it is open. - TemporaryFile = NamedTemporaryFile - -else: - def TemporaryFile(mode='w+b', bufsize=-1, suffix="", - prefix=template, dir=None): - """Create and return a temporary file. - Arguments: - 'prefix', 'suffix', 'directory' -- as for mkstemp. - 'mode' -- the mode argument to os.fdopen (default "w+b"). - 'bufsize' -- the buffer size argument to os.fdopen (default -1). - The file is created as mkstemp() would do it. - - Returns a file object. The file has no name, and will cease to - exist when it is closed. - """ - - if dir is None: - dir = gettempdir() - - if 'b' in mode: - flags = _bin_openflags - else: - flags = _text_openflags - - (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags) - try: - _os.unlink(name) - return _os.fdopen(fd, mode, bufsize) - except: - _os.close(fd) - raise diff --git a/tools/xenctl/lib/utils.py b/tools/xenctl/lib/utils.py deleted file mode 100644 index 69bf779333..0000000000 --- a/tools/xenctl/lib/utils.py +++ /dev/null @@ -1,944 +0,0 @@ -import os, re, socket, string, sys, tempfile, xenctl.ip - -##### Module variables - -"""Location of the Virtual Disk management database. - defaults to /var/db/xen_vdisks.sqlite -""" -VD_DB_FILE = "/var/db/xen_vdisks.sqlite" - -"""VBD expertise level - determines the strictness of the sanity checking. - This mode determines the level of complaints when disk sharing occurs - through the current VBD mappings. - 0 - only allow shared mappings if both domains have r/o access (always OK) - 1 - also allow sharing with one dom r/w and the other r/o - 2 - allow sharing with both doms r/w -""" -VBD_EXPERT_MODE = 0 - -##### Module initialisation - -try: - # try to import sqlite (not everyone will have it installed) - import sqlite -except ImportError: - # on failure, just catch the error, don't do anything - pass - - -##### Networking-related functions - -def get_current_ipaddr(dev='eth0'): - return xenctl.ip.get_current_ipaddr(dev) -def get_current_ipmask(dev='eth0'): - return xenctl.ip.get_current_ipmask(dev) -def get_current_ipgw(dev='eth0'): - return xenctl.ip.get_current_ipgw(dev) -def setup_vfr_rules_for_vif(dom,vif,addr): - return xenctl.ip.setup_vfr_rules_for_vif(dom,vif,addr) -def inet_aton(addr): - return xenctl.ip.inet_aton(addr) -def inet_ntoa(n): - return xenctl.ip.inet_ntoa(n) -def add_offset_to_ip(addr, offset): - return xenctl.ip.add_offset_to_ip(addr, offset) -def check_subnet( ip, network, netmask ): - return xenctl.ip.check_subnet( ip, network, netmask ) - -##### VBD-related Functions - -def blkdev_name_to_number(name): - """Take the given textual block-device name (e.g., '/dev/sda1', - 'hda') and return the device number used by the OS. """ - - if not re.match( '/dev/', name ): - name = '/dev/' + name - - return os.stat(name).st_rdev - -# lookup_blkdev_partn_info( '/dev/sda3' ) -def lookup_raw_partn(partition): - """Take the given block-device name (e.g., '/dev/sda1', 'hda') - and return a dictionary { device, start_sector, - nr_sectors, type } - device: Device number of the given partition - start_sector: Index of first sector of the partition - nr_sectors: Number of sectors comprising this partition - type: 'Disk' or identifying name for partition type - """ - - if not re.match( '/dev/', partition ): - partition = '/dev/' + partition - - drive = re.split( '[0-9]', partition )[0] - - if drive == partition: - fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) - line = fd.readline() - if line: - return [ { 'device' : blkdev_name_to_number(drive), - 'start_sector' : long(0), - 'nr_sectors' : long(line) * 2, - 'type' : 'Disk' } ] - return None - - # determine position on disk - fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' ) - - #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012'] - lines = fd.readlines() - for line in lines: - m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' + - 'size=\s*([0-9]+), Id=\s*(\S+).*$', line) - if m: - return [ { 'device' : blkdev_name_to_number(drive), - 'start_sector' : long(m.group(1)), - 'nr_sectors' : long(m.group(2)), - 'type' : m.group(3) } ] - - return None - -def lookup_disk_uname( uname ): - """Lookup a list of segments for either a physical or a virtual device. - uname [string]: name of the device in the format \'vd:id\' for a virtual - disk, or \'phy:dev\' for a physical device - returns [list of dicts]: list of extents that make up the named device - """ - ( type, d_name ) = string.split( uname, ':' ) - - if type == "phy": - segments = lookup_raw_partn( d_name ) - elif type == "vd": - segments = vd_lookup( d_name ) - - return segments - - -##### Management of the Xen control daemon -##### (c) Keir Fraser, University of Cambridge - -def xend_control_message( message ): - """Takes a textual control message and sends it to the 'xend' Xen - control daemon. Returns a dictionary containing the daemon's multi-part - response.""" - tmpdir = tempfile.mkdtemp() - try: - ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0) - ctl.bind(tmpdir+'/sock') - ctl.sendto(message, '/var/run/xend/management_sock') - data, addr = ctl.recvfrom(2048) - ctl.close() - finally: - if os.path.exists(tmpdir+'/sock'): - os.unlink(tmpdir+'/sock') - if os.path.exists(tmpdir): - os.rmdir(tmpdir) - return eval(data) - - -##### VD Management-related functions - -##### By Mark Williamson, -##### (C) Intel Research Cambridge - -# TODO: -# -# Plenty of room for enhancement to this functionality (contributions -# welcome - and then you get to have your name in the source ;-)... -# -# vd_unformat() : want facilities to unallocate virtual disk -# partitions, possibly migrating virtual disks of them, with checks to see if -# it's safe and options to force it anyway -# -# vd_create() : should have an optional argument specifying a physical -# disk preference - useful to allocate for guest doms to do RAID -# -# vd_undelete() : add ability to "best effort" undelete as much of a -# vdisk as is left in the case that some of it has already been -# reallocated. Some people might still be able to recover some of -# their data this way, even if some of the disk has disappeared. -# -# It'd be nice if we could wipe virtual disks for security purposes - -# should be easy to do this using dev if=/dev/{zero,random} on each -# extent in turn. There could be another optional flag to vd_create -# in order to allow this. -# -# Error codes could be more expressive - i.e. actually tell why the -# error occurred rather than "it broke". Currently the code avoids -# using exceptions to make control scripting simpler and more -# accessible to beginners - therefore probably should just use more -# return codes. -# -# Enhancements / additions to the example scripts are also welcome: -# some people will interact with this code mostly through those -# scripts. -# -# More documentation of how this stuff should be used is always nice - -# if you have a novel configuration that you feel isn't discussed -# enough in the HOWTO (which is currently a work in progress), feel -# free to contribute a walkthrough, or something more substantial. -# - - -def __vd_no_database(): - """Called when no database found - exits with an error - """ - print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE - sys.exit(1) - - -def vd_format(partition, extent_size_mb): - """Format a partition or drive for use a virtual disk storage. - partition [string]: device file representing the partition - extent_size_mb [string]: extent size in megabytes to use on this disk - """ - - if not os.path.isfile(VD_DB_FILE): - vd_init_db(VD_DB_FILE) - - if not re.match( '/dev/', partition ): - partition = '/dev/' + partition - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("select * from vdisk_part where partition = \'" - + partition + "\'") - row = cu.fetchone() - - extent_size = extent_size_mb * 2048 # convert megabytes to sectors - - if not row: - part_info = lookup_raw_partn(partition)[0] - - cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " + - "VALUES ( \'" + partition + "\', " - + str(blkdev_name_to_number(partition)) - + ", " + str(extent_size) + ")") - - - cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents " - + "WHERE vdisk_id = 0") - - max_id, = cu.fetchone() - - if max_id != None: - new_id = max_id + 1 - else: - new_id = 0 - - num_extents = part_info['nr_sectors'] / extent_size - - for i in range(num_extents): - sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id, - part_id, part_extent_no) - VALUES ("""+ str(new_id + i) + ", 0, "\ - + str(blkdev_name_to_number(partition))\ - + ", " + str(num_extents - (i + 1)) + ")" - cu.execute(sql) - - cx.commit() - cx.close() - return 0 - - -def vd_create(size_mb, expiry): - """Create a new virtual disk. - size_mb [int]: size in megabytes for the new virtual disk - expiry [int]: expiry time in seconds from now - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - size = size_mb * 2048 - - cu.execute("SELECT max(vdisk_id) FROM vdisks") - max_id, = cu.fetchone() - new_id = int(max_id) + 1 - - # fetch a list of extents from the expired disks, along with information - # about their size - cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no, - vdisk_extents.part_id, extent_size - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - WHERE expires AND expiry_time <= datetime('now') - ORDER BY expiry_time ASC, vdisk_extent_no DESC - """) # aims to reuse the last extents - # from the longest-expired disks first - - allocated = 0 - - if expiry: - expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" - expires = 1 - else: - expiry_ts = "NULL" - expires = 0 - - # we'll use this to build the SQL statement we want - building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \ - +" VALUES ("+str(new_id)+", "+str(size)+ ", " \ - + str(expires) + ", " + expiry_ts + "); " - - counter = 0 - - while allocated < size: - row = cu.fetchone() - if not row: - print "ran out of space, having allocated %d meg of %d" % (allocated, size) - cx.close() - return -1 - - - (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row - allocated += extent_size - building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \ - + ", " + "vdisk_extent_no = " + str(counter) \ - + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \ - + " AND vdisk_id = " + str(vdisk_id) + "; " - - counter += 1 - - - # this will execute the SQL query we build to store details of the new - # virtual disk and allocate space to it print building_sql - cu.execute(building_sql) - - cx.commit() - cx.close() - return str(new_id) - - -def vd_lookup(id): - """Lookup a Virtual Disk by ID. - id [string]: a virtual disk identifier - Returns [list of dicts]: a list of extents as dicts, containing fields: - device : Linux device number of host disk - start_sector : within the device - nr_sectors : size of this extent - type : set to \'VD Extent\' - - part_device : Linux device no of host partition - part_start_sector : within the partition - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("-- types int") - cu.execute("""SELECT COUNT(*) - FROM vdisks - WHERE (expiry_time > datetime('now') OR NOT expires) - AND vdisk_id = """ + id) - count, = cu.fetchone() - - if not count: - cx.close() - return None - - cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id) - real_size, = cu.fetchone() - - # This query tells PySQLite how to convert the data returned from the - # following query - the use of the multiplication confuses it otherwise ;-) - # This row is significant to PySQLite but is syntactically an SQL comment. - - cu.execute("-- types str, int, int, int") - - # This SQL statement is designed so that when the results are fetched they - # will be in the right format to return immediately. - cu.execute("""SELECT partition, vdisk_part.part_id, - round(part_extent_no * extent_size) as start, - extent_size - - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - - WHERE vdisk_extents.vdisk_id = """ + id - + " ORDER BY vdisk_extents.vdisk_extent_no ASC" - ) - - extent_tuples = cu.fetchall() - - # use this function to map the results from the database into a dict - # list of extents, for consistency with the rest of the code - def transform ((partition, part_device, part_offset, nr_sectors)): - return { - # the disk device this extent is on - for passing to Xen - 'device' : lookup_raw_partn(partition)[0]['device'], - # the offset of this extent within the disk - for passing to Xen - 'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']), - # extent size, in sectors - 'nr_sectors' : nr_sectors, - # partition device this extent is on (useful to know for xenctl.utils fns) - 'part_device' : part_device, - # start sector within this partition (useful to know for xenctl.utils fns) - 'part_start_sector' : part_offset, - # type of this extent - handy to know - 'type' : 'VD Extent' } - - cx.commit() - cx.close() - - extent_dicts = map(transform, extent_tuples) - - # calculate the over-allocation in sectors (happens because - # we allocate whole extents) - allocated_size = 0 - for i in extent_dicts: - allocated_size += i['nr_sectors'] - - over_allocation = allocated_size - real_size - - # trim down the last extent's length so the resulting VBD will be the - # size requested, rather than being rounded up to the nearest extent - extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation - - return extent_dicts - - -def vd_enlarge(vdisk_id, extra_size_mb): - """Create a new virtual disk. - vdisk_id [string] : ID of the virtual disk to enlarge - extra_size_mb [int]: size in megabytes to increase the allocation by - returns [int] : 0 on success, otherwise non-zero - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - extra_size = extra_size_mb * 2048 - - cu.execute("-- types int") - cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id - + " AND (expiry_time > datetime('now') OR NOT expires)") - count, = cu.fetchone() - - if not count: # no such vdisk - cx.close() - return -1 - - cu.execute("-- types int") - cu.execute("""SELECT SUM(extent_size) - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - WHERE vdisks.vdisk_id = """ + vdisk_id) - - real_size, = cu.fetchone() # get the true allocated size - - cu.execute("-- types int") - cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) - - old_size, = cu.fetchone() - - - cu.execute("--- types int") - cu.execute("""SELECT MAX(vdisk_extent_no) - FROM vdisk_extents - WHERE vdisk_id = """ + vdisk_id) - - counter = cu.fetchone()[0] + 1 # this stores the extent numbers - - - # because of the extent-based allocation, the VD may already have more - # allocated space than they asked for. Find out how much we really - # need to add. - add_size = extra_size + old_size - real_size - - # fetch a list of extents from the expired disks, along with information - # about their size - cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no, - vdisk_extents.part_id, extent_size - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - WHERE expires AND expiry_time <= datetime('now') - ORDER BY expiry_time ASC, vdisk_extent_no DESC - """) # aims to reuse the last extents - # from the longest-expired disks first - - allocated = 0 - - building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\ - + " WHERE vdisk_id = " + vdisk_id + "; " - - while allocated < add_size: - row = cu.fetchone() - if not row: - cx.close() - return -1 - - (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row - allocated += extent_size - building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id \ - + ", " + "vdisk_extent_no = " + str(counter) \ - + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \ - + " AND vdisk_id = " + str(dead_vd_id) + "; " - - counter += 1 - - - # this will execute the SQL query we build to store details of the new - # virtual disk and allocate space to it print building_sql - cu.execute(building_sql) - - cx.commit() - cx.close() - return 0 - - -def vd_undelete(vdisk_id, expiry_time): - """Create a new virtual disk. - vdisk_id [int]: size in megabytes for the new virtual disk - expiry_time [int]: expiry time, in seconds from now - returns [int]: zero on success, non-zero on failure - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - if vdisk_id == '0': # undeleting vdisk 0 isn't sane! - return -1 - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("-- types int") - cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id) - count, = cu.fetchone() - - if not count: - cx.close() - return -1 - - cu.execute("-- types int") - cu.execute("""SELECT SUM(extent_size) - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - WHERE vdisks.vdisk_id = """ + vdisk_id) - - real_size, = cu.fetchone() # get the true allocated size - - - cu.execute("-- types int") - cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) - - old_size, = cu.fetchone() - - if real_size < old_size: - cx.close() - return -1 - - if expiry_time == 0: - expires = '0' - else: - expires = '1' - - # this will execute the SQL query we build to store details of the new - # virtual disk and allocate space to it print building_sql - cu.execute("UPDATE vdisks SET expiry_time = datetime('now','" - + str(expiry_time) + " seconds'), expires = " + expires - + " WHERE vdisk_id = " + vdisk_id) - - cx.commit() - cx.close() - return 0 - - - - -def vd_list(): - """Lists all the virtual disks registered in the system. - returns [list of dicts] - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("""SELECT vdisk_id, size, expires, expiry_time - FROM vdisks - WHERE (NOT expires) OR expiry_time > datetime('now') - """) - - ret = cu.fetchall() - - cx.close() - - def makedicts((vdisk_id, size, expires, expiry_time)): - return { 'vdisk_id' : str(vdisk_id), 'size': size, - 'expires' : expires, 'expiry_time' : expiry_time } - - return map(makedicts, ret) - - -def vd_refresh(id, expiry): - """Change the expiry time of a virtual disk. - id [string] : a virtual disk identifier - expiry [int] : expiry time in seconds from now (0 = never expire) - returns [int]: zero on success, non-zero on failure - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("-- types int") - cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id - + " AND (expiry_time > datetime('now') OR NOT expires)") - count, = cu.fetchone() - - if not count: - cx.close() - return -1 - - if expiry: - expires = 1 - expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" - else: - expires = 0 - expiry_ts = "NULL" - - cu.execute("UPDATE vdisks SET expires = " + str(expires) - + ", expiry_time = " + expiry_ts - + " WHERE (expiry_time > datetime('now') OR NOT expires)" - + " AND vdisk_id = " + id) - - cx.commit() - cx.close() - - return 0 - - -def vd_delete(id): - """Deletes a Virtual Disk, making its extents available for future VDs. - id [string] : identifier for the virtual disk to delete - returns [int] : 0 on success, -1 on failure (VD not found - or already deleted) - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("-- types int") - cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id - + " AND (expiry_time > datetime('now') OR NOT expires)") - count, = cu.fetchone() - - if not count: - cx.close() - return -1 - - cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')" - + " WHERE vdisk_id = " + id) - - cx.commit() - cx.close() - - return 0 - - -def vd_freespace(): - """Returns the amount of free space available for new virtual disks, in MB - returns [int] : free space for VDs in MB - """ - - if not os.path.isfile(VD_DB_FILE): - __vd_no_database() - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("-- types int") - - cu.execute("""SELECT SUM(extent_size) - FROM vdisks NATURAL JOIN vdisk_extents - NATURAL JOIN vdisk_part - WHERE expiry_time <= datetime('now') AND expires""") - - sum, = cu.fetchone() - - cx.close() - - return sum / 2048 - - -def vd_init_db(path): - """Initialise the VD SQLite database - path [string]: path to the SQLite database file - """ - - cx = sqlite.connect(path) - cu = cx.cursor() - - cu.execute( - """CREATE TABLE vdisk_extents - ( vdisk_extent_no INT, - vdisk_id INT, - part_id INT, - part_extent_no INT ) - """) - - cu.execute( - """CREATE TABLE vdisk_part - ( part_id INT, - partition VARCHAR, - extent_size INT ) - """) - - cu.execute( - """CREATE TABLE vdisks - ( vdisk_id INT, - size INT, - expires BOOLEAN, - expiry_time TIMESTAMP ) - """) - - - cu.execute( - """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time ) - VALUES ( 0, 0, 1, datetime('now') ) - """) - - cx.commit() - cx.close() - - VD_DB_FILE = path - - - -def vd_cp_to_file(vdisk_id,filename): - """Writes the contents of a specified vdisk out into a disk file, leaving - the original copy in the virtual disk pool.""" - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - extents = vd_lookup(vdisk_id) - - if not extents: - return -1 - - file_idx = 0 # index into source file, in sectors - - for i in extents: - cu.execute("""SELECT partition, extent_size FROM vdisk_part - WHERE part_id = """ + str(i['part_device'])) - - (partition, extent_size) = cu.fetchone() - - os.system("dd bs=1b if=" + partition + " of=" + filename - + " skip=" + str(i['part_start_sector']) - + " seek=" + str(file_idx) - + " count=" + str(i['nr_sectors']) - + " > /dev/null") - - file_idx += i['nr_sectors'] - - cx.close() - - return 0 # should return -1 if something breaks - - -def vd_mv_to_file(vdisk_id,filename): - """Writes a vdisk out into a disk file and frees the space originally - taken within the virtual disk pool. - vdisk_id [string]: ID of the vdisk to write out - filename [string]: file to write vdisk contents out to - returns [int]: zero on success, nonzero on failure - """ - - if vd_cp_to_file(vdisk_id,filename): - return -1 - - if vd_delete(vdisk_id): - return -1 - - return 0 - - -def vd_read_from_file(filename,expiry): - """Reads the contents of a file directly into a vdisk, which is - automatically allocated to fit. - filename [string]: file to read disk contents from - returns [string] : vdisk ID for the destination vdisk - """ - - size_bytes = os.stat(filename).st_size - - (size_mb,leftover) = divmod(size_bytes,1048580) # size in megabytes - if leftover > 0: size_mb += 1 # round up if not an exact number of MB - - vdisk_id = vd_create(size_mb, expiry) - - if vdisk_id < 0: - return -1 - - cx = sqlite.connect(VD_DB_FILE) - cu = cx.cursor() - - cu.execute("""SELECT partition, extent_size, part_extent_no - FROM vdisk_part NATURAL JOIN vdisk_extents - WHERE vdisk_id = """ + vdisk_id + """ - ORDER BY vdisk_extent_no ASC""") - - extents = cu.fetchall() - - size_sectors = size_mb * 2048 # for feeding to dd - - file_idx = 0 # index into source file, in sectors - - def write_extent_to_vd((partition, extent_size, part_extent_no), - file_idx, filename): - """Write an extent out to disk and update file_idx""" - - os.system("dd bs=512 if=" + filename + " of=" + partition - + " skip=" + str(file_idx) - + " seek=" + str(part_extent_no * extent_size) - + " count=" + str(min(extent_size, size_sectors - file_idx)) - + " > /dev/null") - - return extent_size - - for i in extents: - file_idx += write_extent_to_vd(i, file_idx, filename) - - cx.close() - - return vdisk_id - - - - -def vd_extents_validate(new_extents,new_writeable): - """Validate the extents against the existing extents. - Complains if the list supplied clashes against the extents that - are already in use in the system. - new_extents [list of dicts]: list of new extents, as dicts - new_writeable [int]: 1 if they are to be writeable, 0 otherwise - returns [int]: either the expertise level of the mapping if it doesn't - exceed VBD_EXPERT_MODE or -1 if it does (error) - """ - - import Xc # this is only needed in this function - - xc = Xc.new() - - ##### Probe for explicitly created virtual disks and build a list - ##### of extents for comparison with the ones that are being added - - probe = xc.vbd_probe() - - old_extents = [] # this will hold a list of all existing extents and - # their writeable status, as a list of (device, - # start, size, writeable?) tuples - - for vbd in probe: - this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd']) - for vbd_ext in this_vbd_extents: - vbd_ext['writeable'] = vbd['writeable'] - old_extents.append(vbd_ext) - - ##### Now scan /proc/mounts for compile a list of extents corresponding to - ##### any devices mounted in DOM0. This list is added on to old_extents - - regexp = re.compile("/dev/(\S*) \S* \S* (..).*") - fd = open('/proc/mounts', "r") - - while True: - line = fd.readline() - if not line: # if we've run out of lines then stop reading - break - - m = regexp.match(line) - - # if the regexp didn't match then it's probably a line we don't - # care about - skip to next line - if not m: - continue - - # lookup the device - ext_list = lookup_raw_partn(m.group(1)) - - # if lookup failed, skip to next mounted device - if not ext_list: - continue - - # set a writeable flag as appropriate - for ext in ext_list: - ext['writeable'] = m.group(2) == 'rw' - - # now we've got here, the contents of ext_list are in a - # suitable format to be added onto the old_extents list, ready - # for checking against the new extents - - old_extents.extend(ext_list) - - fd.close() # close /proc/mounts - - ##### By this point, old_extents contains a list of extents, in - ##### dictionary format corresponding to every extent of physical - ##### disk that's either part of an explicitly created VBD, or is - ##### mounted under DOM0. We now check these extents against the - ##### proposed additions in new_extents, to see if a conflict will - ##### happen if they are added with write status new_writeable - - level = 0 # this'll accumulate the max warning level - - # Search for clashes between the new extents and the old ones - # Takes time O(len(new_extents) * len(old_extents)) - for new_ext in new_extents: - for old_ext in old_extents: - if(new_ext['device'] == old_ext['device']): - - new_ext_start = new_ext['start_sector'] - new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1 - - old_ext_start = old_ext['start_sector'] - old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1 - - if((old_ext_start <= new_ext_start <= old_ext_end) or - (old_ext_start <= new_ext_end <= old_ext_end)): - if (not old_ext['writeable']) and new_writeable: - level = max(1,level) - elif old_ext['writeable'] and (not new_writeable): - level = max(1,level) - elif old_ext['writeable'] and new_writeable: - level = max(2,level) - - - ##### level now holds the warning level incurred by the current - ##### VBD setup and we complain appropriately to the user - - - if level == 1: - print >> sys.stderr, """Warning: one or more hard disk extents - writeable by one domain are also readable by another.""" - elif level == 2: - print >> sys.stderr, """Warning: one or more hard disk extents are - writeable by two or more domains simultaneously.""" - - if level > VBD_EXPERT_MODE: - print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed - at the current safety level (%d).""" % VBD_EXPERT_MODE - level = -1 - - return level - diff --git a/tools/xenctl/setup.py b/tools/xenctl/setup.py deleted file mode 100644 index 03f3f1e25c..0000000000 --- a/tools/xenctl/setup.py +++ /dev/null @@ -1,19 +0,0 @@ - -from distutils.core import setup, Extension -import sys - -modules = [ 'xenctl.console_client', 'xenctl.utils', 'xenctl.ip' ] - -# We need the 'tempfile' module from Python 2.3. We install this ourselves -# if the installed Python is older than 2.3. -major = sys.version_info[0] -minor = sys.version_info[1] -if major == 2 and minor < 3: - modules.append('xenctl.tempfile') - -setup(name = 'xenctl', - version = '1.0', - py_modules = modules, - package_dir = { 'xenctl' : 'lib' }, - ) - diff --git a/tools/xu/Makefile b/tools/xu/Makefile new file mode 100644 index 0000000000..6b31fd1f8b --- /dev/null +++ b/tools/xu/Makefile @@ -0,0 +1,15 @@ + +all: + python setup.py build + +install: all + if [ "$(prefix)" = "" ]; then \ + python setup.py install; \ + elif [ "$(dist)" = "yes" ]; then \ + python setup.py install --home="$(prefix)"; \ + else \ + python setup.py install --root="$(prefix)"; \ + fi + +clean: + rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm